﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace MathService.Functions.Plotter.GraphComponents
{
    public class BarGraph : Graph
    {
        private readonly BasicBar basicBar;
        private Color aboveRangeColor = Color.Salmon;
        private float aboveRangeValue = 70f;
        private Color barColor = Color.Lime;
        private Graduation barGraduation = Graduation.Edge2;
        private Orientation barOrientation = Orientation.Vertical;
        private float barValue = 35f;
        private Color belowRangeColor = Color.Thistle;
        private float belowRangeValue = 30f;
        private Color graphBorderColor = Color.Black;
        private float maximumValue = 100f;
        private float minimumValue;
        private bool showRangeLines = true;
        private bool showRangeValues;
        private TextAlignment valueAlignment = TextAlignment.Smart;

        public BarGraph()
        {
            InitializeComponent();
            basicBar = new BasicBar();
            SetStyle(ControlStyles.DoubleBuffer | ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint,
                          true);
            UpdateStyles();
        }

        [Category("Appearance"), Description("The color to display if the value is above normal"),
         DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Browsable(true)]
        public Color AboveRangeColor
        {
            get { return aboveRangeColor; }
            set
            {
                aboveRangeColor = value;
                RefreshDisplay();
            }
        }

        [Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
         Category("Appearance"),
         Description("A value beyond which the readings are above normal. The graph can be displayed in a different color if it goes above this range.")]
        public float AboveRangeValue
        {
            get { return aboveRangeValue; }
            set
            {
                aboveRangeValue = value;
                RefreshDisplay();
            }
        }

        [Description("Color of the bar"), Category("Appearance"), Browsable(true),
         DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Color BarColor
        {
            get { return barColor; }
            set
            {
                barColor = value;
                RefreshDisplay();
            }
        }

        [Description("The location where the graduations must appear"), Browsable(true),
         DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Category("Appearance")]
        public Graduation BarGraduation
        {
            get { return barGraduation; }
            set
            {
                barGraduation = value;
                RefreshDisplay();
            }
        }

        [Browsable(true), Description("Bar orientation, whether horizontal or vertical"),
         DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Category("Appearance")]
        public Orientation BarOrientation
        {
            get { return barOrientation; }
            set
            {
                barOrientation = value;
                RefreshDisplay();
            }
        }

        [Description("Current value of the bar. Gets or sets the value to display on the bar"), Browsable(true),
         DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Category("Appearance")]
        public float BarValue
        {
            get { return barValue; }
            set
            {
                if(barValue.Equals(value)) return;
                barValue = value;
                RefreshDisplay();
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
         Description("The color to display if the value is below normal"), Category("Appearance"), Browsable(true)]
        public Color BelowRangeColor
        {
            get { return belowRangeColor; }
            set
            {
                belowRangeColor = value;
                RefreshDisplay();
            }
        }

        [Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
         Category("Appearance"),
         Description("A value beyond which the readings are below normal. The graph can be displayed in a different color if it goes below this range")]
        public float BelowRangeValue
        {
            get { return belowRangeValue; }
            set
            {
                belowRangeValue = value;
                RefreshDisplay();
            }
        }

        [Category("Appearance"), Description("Color of the border of the filled up portion of the graph"),
         DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Browsable(true)]
        public Color BorderColor
        {
            get { return graphBorderColor; }
            set
            {
                graphBorderColor = value;
                RefreshDisplay();
            }
        }

        [Browsable(false), Category("Appearance"),
         DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
         Description("Color of the graph's area (This property is not valid for the bar graph)")]
        public override Color GraphAreaColor { get { return base.GraphAreaColor; } set { base.GraphAreaColor = value; } }

        [Category("Appearance"), Description("Style of the gridlines (This property is not valid for the bar graph)"),
         DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Browsable(false)]
        public override GridStyles Gridlines { get { return base.Gridlines; } set { base.Gridlines = value; } }

        [Category("Appearance"), Browsable(true),
         DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
         Description("Maximum value of the bar")]
        public float MaximumValue
        {
            get { return maximumValue; }
            set
            {
                maximumValue = value;
                RefreshDisplay();
            }
        }

        [Browsable(true), Category("Appearance"), Description("Minimum value of the bar"),
         DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public float MinimumValue
        {
            get { return minimumValue; }
            set
            {
                minimumValue = value;
                RefreshDisplay();
            }
        }

        [Category("Appearance"),
         Description("Flag indicating whether lines for above and below normal limits are to be displayed"),
         Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public bool ShowRangeLines
        {
            get { return showRangeLines; }
            set
            {
                showRangeLines = value;
                RefreshDisplay();
            }
        }

        [Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
         Description("Flag indicating whether the values of above and below ranges are to be displayed"),
         Category("Appearance")]
        public bool ShowRangeValues
        {
            get { return showRangeValues; }
            set
            {
                showRangeValues = value;
                RefreshDisplay();
            }
        }

        [Browsable(true), Category("Appearance"), Description("The alignment of the value's text"),
         DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public TextAlignment ValueAlignment
        {
            get { return valueAlignment; }
            set
            {
                valueAlignment = value;
                RefreshDisplay();
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Description("Color of the X axis (This property is not valid for the bar graph)"),
         Category("Appearance"), Browsable(false)]
        public override Color XAxisColor { get { return base.XAxisColor; } set { base.XAxisColor = value; } }

        [Description("Color of the Y axis (This property is not valid for the bar graph)"), Browsable(false)
        , DesignerSerializationVisibility(DesignerSerializationVisibility.Visible), Category("Appearance")]
        public override Color YAxisColor { get { return base.YAxisColor; } set { base.YAxisColor = value; } }

        //protected override void Dispose(bool disposing) { base.Dispose(disposing); }

        public override void Draw(Graphics graphics)
        {
            graphics.SmoothingMode = SmoothingMode.AntiAlias;
            var lv_BarColor = barColor;
            if(barValue > aboveRangeValue)
                lv_BarColor = aboveRangeColor;
            else if(barValue < belowRangeValue)
                lv_BarColor = belowRangeColor;
            lv_BarColor = Color.FromArgb(Transparency, lv_BarColor);
            basicBar.BarColor = lv_BarColor;
            if(((ClientRectangle.Width != 0) && (ClientRectangle.Height != 0))
               && (MinimumValue < MaximumValue))
            {
                basicBar.ClientRectangle = ClientRectangle;
                basicBar.MinimumValue = minimumValue;
                basicBar.MaximumValue = maximumValue;
                basicBar.BarValue = BarValue;
                basicBar.AboveRangeValue = AboveRangeValue;
                basicBar.BelowRangeValue = BelowRangeValue;
                basicBar.BarOrientation = barOrientation;
                basicBar.ForeColor = ForeColor;
                basicBar.ValueFormat = ValueFormat;
                basicBar.ValueAlignment = valueAlignment;
                basicBar.TextFont = Font;
                basicBar.ShowRangeLines = showRangeLines;
                basicBar.ShowRangeValues = showRangeValues;
                basicBar.BorderColor = graphBorderColor;
                basicBar.BarGraduation = barGraduation;
                basicBar.OutOfRangeArrowColor = BarColor;
                basicBar.Draw(graphics);
            }
        }

        private void InitializeComponent()
        {
            Name = "BarGraph";
            Size = new Size(0x70, 360);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if(!Visible) return;
            var graphics = e.Graphics;
            Draw(graphics);
            base.OnPaint(e);
        }
    }
}
